#include <boost/shared_ptr.hpp>

#include "engine/result_codes.h"
#include "engine/dator.h"
#include "engine/settings_manager.h"

#include "cppunit/TestFixture.h"
#include "cppunit/extensions/HelperMacros.h"

using namespace engine;

class SettingsManagerTest : public CppUnit::TestFixture {
    CPPUNIT_TEST_SUITE(SettingsManagerTest);
    
    CPPUNIT_TEST(testRegisterVariable);
    CPPUNIT_TEST(testSetVariable);
    CPPUNIT_TEST(testParseFile);
    CPPUNIT_TEST_SUITE_END();

public:
    void setUp() { 
        int_var1_ = 0;
        float_var1_ = 0.0f;
        bool_var1_ = false;

        string_var1_ = "";
        string_var2_ = "";

        setting1 = boost::shared_ptr<Dator>(new IntSetting(int_var1_));
        setting2 = boost::shared_ptr<Dator>(new FloatSetting(float_var1_));
        setting3 = boost::shared_ptr<Dator>(new StringSetting(string_var1_));
        setting4 = boost::shared_ptr<Dator>(new StringSetting(string_var2_));
        setting5 = boost::shared_ptr<Dator>(new BoolSetting(bool_var1_));

    }

    void tearDown() {
    
    }

    void testRegisterVariable() {

        

        std::string path, name;
        int result_code;

        name = "setting1";
        SettingsManager::ResolveName(path, name);
        result_code = SettingsManager::RegisterVariable(name, setting1);
        CPPUNIT_ASSERT(result_code::Equals(result_code, base::OK_OK));

        name = "setting2";
        SettingsManager::ResolveName(path, name);
        result_code = SettingsManager::RegisterVariable(name, setting2);
        CPPUNIT_ASSERT(result_code::Equals(result_code, base::OK_OK));

        name = "setting3";
        SettingsManager::ResolveName(path, name);
        result_code = SettingsManager::RegisterVariable(name, setting3);
        CPPUNIT_ASSERT(result_code::Equals(result_code, base::OK_OK));

        SettingsManager::AppendGroupName("group1", path);

        name = "setting3";
        SettingsManager::ResolveName(path, name);
        result_code = SettingsManager::RegisterVariable(name, setting4);
        CPPUNIT_ASSERT(result_code::Equals(result_code, base::OK_OK));

        name = "setting4";
        SettingsManager::ResolveName(path, name);
        result_code = SettingsManager::RegisterVariable(name, setting5);
        CPPUNIT_ASSERT(result_code::Equals(result_code, base::OK_OK));

        name = "setting6";
        SettingsManager::ResolveName(path, name);
        result_code = SettingsManager::RegisterVariable(name, boost::shared_ptr<Dator>((Dator*)NULL));
        CPPUNIT_ASSERT(result_code::Equals(result_code, base::ER_NULL_POINTER));
    }

    void testSetVariable()
    {
        std::string path, name;
        int result_code;
        
        name = "setting1";
        SettingsManager::ResolveName(path, name);
        result_code = SettingsManager::RegisterVariable(name,setting1);
        result_code = SettingsManager::SetVariable(name, "44");
        CPPUNIT_ASSERT(result_code::Equals(result_code, base::OK_OK));
        CPPUNIT_ASSERT_EQUAL(44, int_var1_);

        name = "setting2";
        SettingsManager::ResolveName(path, name);
        SettingsManager::RegisterVariable(name, setting2);
        result_code = SettingsManager::SetVariable(name, "55.66");
        CPPUNIT_ASSERT(result_code::Equals(result_code, base::OK_OK));
        CPPUNIT_ASSERT_EQUAL(55.66f, float_var1_);

        name = "setting6";
        result_code = SettingsManager::SetVariable(name, "false");
        CPPUNIT_ASSERT(result_code::Equals(result_code, engine::ER_SETTING_NOT_FOUND));
    }

    void testParseFile() {
        std::string path, name, global_name;
        int result_code;
        
        name = "setting1";
        SettingsManager::ResolveName(path, name);
        SettingsManager::RegisterVariable(name, setting1);

        name = "setting2";
        SettingsManager::ResolveName(path, name);
        SettingsManager::RegisterVariable(name, setting2);

        name = "setting3";
        SettingsManager::ResolveName(path, name);
        SettingsManager::RegisterVariable(name, setting3);

        SettingsManager::AppendGroupName("group1", path);

        name = "setting3";
        SettingsManager::ResolveName(path, name);
        SettingsManager::RegisterVariable(name, setting4);

        name = "setting4";
        SettingsManager::ResolveName(path, name);
        SettingsManager::RegisterVariable(name, setting5);

        result_code = SettingsManager::ParseXmlFile("bogus file name.xml");
        CPPUNIT_ASSERT(result_code::Equals(result_code, base::ER_FAIL_TO_READ_FILE));

        result_code = SettingsManager::ParseXmlFile("../unit_tests/test_settings.xml");
        CPPUNIT_ASSERT(result_code::Equals(result_code, base::OK_TRUE));
        CPPUNIT_ASSERT_EQUAL(4, int_var1_);
        CPPUNIT_ASSERT_EQUAL(4.0f, float_var1_);
        CPPUNIT_ASSERT_EQUAL(string_var1_.compare("cat"), 0);
        CPPUNIT_ASSERT_EQUAL(string_var2_.compare("moo moo"), 0);
        CPPUNIT_ASSERT_EQUAL(true, bool_var1_);

        result_code = SettingsManager::ParseIniFile("bogus file name.ini");
        CPPUNIT_ASSERT(result_code::Equals(result_code, base::ER_FAIL_TO_READ_FILE));

        result_code = SettingsManager::ParseIniFile("../unit_tests/test_settings.ini");
        CPPUNIT_ASSERT(result_code::Equals(result_code, base::OK_TRUE));
        CPPUNIT_ASSERT_EQUAL(6, int_var1_);
        CPPUNIT_ASSERT_EQUAL(2.34f, float_var1_);
        CPPUNIT_ASSERT_EQUAL(string_var1_.compare("tac"), 0);
        CPPUNIT_ASSERT_EQUAL(string_var2_.compare("oom oom"),0);
        CPPUNIT_ASSERT_EQUAL(false, bool_var1_);

        result_code = SettingsManager::ParseFile("bogus file name.xml");
        CPPUNIT_ASSERT(result_code::Equals(result_code, base::ER_FAIL_TO_READ_FILE));

        result_code = SettingsManager::ParseFile("../unit_tests/test_settings.xml");
        CPPUNIT_ASSERT(result_code::Equals(result_code, base::OK_TRUE));
        CPPUNIT_ASSERT_EQUAL(4, int_var1_);
        CPPUNIT_ASSERT_EQUAL(4.0f, float_var1_);
        CPPUNIT_ASSERT_EQUAL(string_var1_.compare("cat"), 0);
        CPPUNIT_ASSERT_EQUAL(string_var2_.compare("moo moo"), 0);
        CPPUNIT_ASSERT_EQUAL(true, bool_var1_);
    }

private:
    int int_var1_;
    float float_var1_;
    std::string string_var1_, string_var2_;
    bool bool_var1_;

    boost::shared_ptr<Dator> setting1, setting2, setting3, setting4, setting5;
    

};

CPPUNIT_TEST_SUITE_REGISTRATION(SettingsManagerTest);